/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.comac.ins.common.core.exception.ServiceException;
import com.comac.ins.common.core.utils.StreamUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.core.utils.file.FileUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.common.oss.core.OssClient;
import com.comac.ins.common.oss.entity.UploadResult;
import com.comac.ins.common.oss.enumd.AccessPolicyType;
import com.comac.ins.common.oss.factory.OssFactory;
import com.comac.ins.common.satoken.utils.LoginHelper;
import com.comac.ins.isfd.constant.enums.IsfdImportMethodEnum;
import com.comac.ins.isfd.constant.enums.IsfdMongoQueryLogicalOperatorEnum;
import com.comac.ins.isfd.constant.enums.IsfdMongoQueryOperatorEnum;
import com.comac.ins.isfd.domain.IsfdDatabaseModelConfig;
import com.comac.ins.isfd.domain.IsfdDatabaseMongoQuery;
import com.comac.ins.isfd.domain.bo.IsfdDatabaseDataImportRecordBo;
import com.comac.ins.isfd.domain.bo.IsfdModelBo;
import com.comac.ins.isfd.domain.vo.*;
import com.comac.ins.isfd.mapper.IsfdBusinessDatabaseRefMapper;
import com.comac.ins.isfd.mapper.IsfdDatabaseModelConfigMapper;
import com.comac.ins.isfd.mapper.ModelMapper;
import com.comac.ins.isfd.service.IIsfdDatabaseDataImportRecordService;
import com.comac.ins.isfd.service.IIsfdDatabaseMongoService;
import com.comac.ins.isfd.service.IsfdCompositeModelService;
import com.comac.ins.isfd.util.DateUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.bson.Document;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 模型库service层接口实现层
 *
 * @author hxloongs
 * @date 2024-7-1
 */
@RequiredArgsConstructor
@Service
public class IsfdCompositeModelServiceImpl implements IsfdCompositeModelService {

    @Autowired
    private final ModelMapper modelMapper;

    @Autowired
    private final IsfdDatabaseModelConfigMapper isfdDatabaseModelConfigMapper;
    @Autowired
    private final IsfdDatabaseDataManagementServiceImpl isfdDatabaseDataManagementService;
    @Autowired
    private IIsfdDatabaseMongoService mongoService;
    @Autowired
    private IIsfdDatabaseDataImportRecordService importRecordService;
    @Autowired
    private IsfdBusinessDatabaseRefMapper isfdBusinessDatabaseRefMapper;
    @Override
    public List<ModelCountObjectVo> listCount() {
        List<ModelCountObjectVo> result = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.select("file_suffix", "COUNT(*) as total_count");
        queryWrapper.groupBy("file_suffix");
        List<Map<String, Object>> list = modelMapper.selectMaps(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach((m -> {
                result.add(new ModelCountObjectVo((String) m.get("file_suffix"), (Long) m.get("total_count")));
            }));
        }
        return result;
    }

    @Override
    public List<ModelCountResultObjectVo> listApplicableCountByField(String field) {
        List<ModelCountResultObjectVo> result = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper<>();
        String modelColumn = "applicable_models";
        queryWrapper.select(field, "COUNT(*) as total_count", modelColumn);
        queryWrapper.groupBy(field, modelColumn);

        List<Map<String, Object>> list = modelMapper.selectMaps(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach((m -> {
                result.add(new ModelCountResultObjectVo(null, (String) m.get(field), (String) m.get(modelColumn), (Long) m.get("total_count")));
            }));
        }
        return result;
    }

    @Override
    public List<ModelCountResultObjectVo> listTimeCount(String field, Date startTime, Date endTime) {
        List<ModelCountResultObjectVo> result = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper<>();
        // 判断 field 是否为空，如果为空则不按该字段分组
        if (StringUtils.isEmpty(field)) {
            queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m') as month", "COUNT(*) as total_count");
            queryWrapper.groupBy("month");
        } else {
            queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m') as month", field + " as field_value", "COUNT(*) as total_count");
            queryWrapper.groupBy("month", "field_value");
        }

        if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
            queryWrapper.between("create_time", startTime, endTime);
        } else if (Objects.nonNull(startTime)) {
            queryWrapper.ge("create_time", startTime);
        } else if (Objects.nonNull(endTime)) {
            queryWrapper.le("create_time", endTime);
        }

        List<Map<String, Object>> list = modelMapper.selectMaps(queryWrapper);

        // 获取指定时间范围内的所有月份
        List<String> allMonths = DateUtils.getAllMonthsBetween(startTime, endTime);
        Set<String> fieldValues = list.stream()
            .filter(m -> m.get("field_value") != null)
            .map(m -> (String) m.get("field_value"))
            .collect(Collectors.toSet());

        // 如果没有指定 field，只用月份显示
        if (StringUtils.isEmpty(field)) {
            allMonths.forEach(month -> {
                Long count = list.stream()
                    .filter(m -> month.equals(m.get("month")))
                    .map(m -> (Long) m.get("total_count"))
                    .findFirst()
                    .orElse(0L);
                result.add(new ModelCountResultObjectVo(month, "", null, count));
            });
        } else {
            // 对每个月和每个字段值进行组合，确保没有数据的组合也显示 totalCount=0
            for (String month : allMonths) {
                for (String fieldValue : fieldValues) {
                    Long count = list.stream()
                        .filter(m -> month.equals(m.get("month")) && fieldValue.equals(m.get("field_value")))
                        .map(m -> (Long) m.get("total_count"))
                        .findFirst()
                        .orElse(0L);
                    result.add(new ModelCountResultObjectVo(month, fieldValue, null, count));
                }
            }
        }
        return result;
    }

    @Override
    public TableDataInfo<IsfdCompositeModelVo> queryPageList(IsfdModelBo bo, PageQuery pageQuery) {
        // 构建查询条件
        List<IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition> conditions = new ArrayList<>();
        IsfdDatabaseMongoQuery queryCondition = new IsfdDatabaseMongoQuery();
        IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition itemCondition = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
        if(com.anwen.mongo.toolkit.StringUtils.isNotBlank(bo.getModelName())){
            itemCondition.setFieldName("model_name");
            itemCondition.setValue(bo.getModelName());
            itemCondition.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.AND.getValue());
            itemCondition.setOperator(IsfdMongoQueryOperatorEnum.LIKE.getValue());
            conditions.add(itemCondition);
        }
        if(com.anwen.mongo.toolkit.StringUtils.isNotBlank(bo.getModelType())){
            itemCondition.setFieldName("model_type");
            itemCondition.setValue(bo.getModelType());
            itemCondition.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.AND.getValue());
            itemCondition.setOperator(IsfdMongoQueryOperatorEnum.LIKE.getValue());
            conditions.add(itemCondition);
        }
        if(com.anwen.mongo.toolkit.StringUtils.isNotBlank(bo.getBusinessScenarios())){
            itemCondition.setFieldName("business_scenarios");
            itemCondition.setValue(bo.getBusinessScenarios());
            itemCondition.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.AND.getValue());
            itemCondition.setOperator(IsfdMongoQueryOperatorEnum.LIKE.getValue());
            conditions.add(itemCondition);
        }
        conditions.add(itemCondition);
        queryCondition.setConditions(conditions);
        IsfdDatabaseModelConfig modelConfig = isfdDatabaseModelConfigMapper.selectModelByModelName("复合材料模型管理通用模型");
        if(Objects.nonNull(pageQuery.getPageNum())) {
            pageQuery.setPageNum(pageQuery.getPageNum());
        }else{
            pageQuery.setPageNum(1);
        }
        if(Objects.nonNull(pageQuery.getPageSize())) {
            pageQuery.setPageSize(pageQuery.getPageSize());
        }else{
            pageQuery.setPageSize(10);
        }
        queryCondition.setPageQuery(pageQuery);
        Long tableDataCount = mongoService.count(modelConfig.getTableName());
        List<Document> documents = isfdDatabaseDataManagementService.queryDataByModelHasRecord(modelConfig.getId(),queryCondition);
        // 循环遍历查询结果
        List<IsfdCompositeModelVo> resultList = new ArrayList<>();
        for (Document document : documents) {
            IsfdCompositeModelVo isfdCompositeModelVo = new IsfdCompositeModelVo();
            isfdCompositeModelVo.setApplicableModels(document.getString("applicable_models"));
            isfdCompositeModelVo.setModelName(document.getString("model_name"));
            isfdCompositeModelVo.setModelType(document.getString("model_type"));
            isfdCompositeModelVo.setModelSeries(document.getString("model_series"));
            isfdCompositeModelVo.setLoadConditions(document.getString("load_conditions"));
            isfdCompositeModelVo.setModelScope(document.getString("model_scope"));
            isfdCompositeModelVo.setBusinessScenarios(document.getString("business_scenarios"));
            isfdCompositeModelVo.setModelDescription(document.getString("model_description"));
            isfdCompositeModelVo.setSourceMethods(document.getString("source_methods"));
            isfdCompositeModelVo.setCreateBy(document.getString("create_by"));
            isfdCompositeModelVo.setFileName(document.getString("file_name"));
            isfdCompositeModelVo.setOriginalName(document.getString("original_name"));
            isfdCompositeModelVo.setFileSuffix(document.getString("file_suffix"));
            isfdCompositeModelVo.setService(document.getString("service"));
            isfdCompositeModelVo.setUrl(document.getString("url"));
            isfdCompositeModelVo.setCreateTime(document.getDate("create_time"));
            isfdCompositeModelVo.setId(document.getString("_id"));
            isfdCompositeModelVo.setModelId(document.getString("_id"));
            resultList.add(isfdCompositeModelVo);
        }
        Page<IsfdCompositeModelVo> result = new Page<>();
        List<IsfdCompositeModelVo> filterResult = StreamUtils.toList(resultList, this::matchingUrl);
        result.setRecords(filterResult);
        result.setCurrent(pageQuery.getPageNum());
        result.setSize(pageQuery.getPageSize());
        result.setTotal(tableDataCount);
        return TableDataInfo.build(result);
    }

    @Override
    public Boolean deleteWithValidByIds(String id, Boolean isValid) {
        try{
            IsfdDatabaseModelConfig modelConfig = isfdDatabaseModelConfigMapper.selectModelByModelName("复合材料模型管理通用模型");
            Document document = mongoService.findById(modelConfig.getTableName(), id);
            OssClient storage = OssFactory.instance(document.getString("service"));
            storage.delete(document.getString("url"));
            // 删除mongo数据
            mongoService.deleteByIds(modelConfig.getTableName(), Collections.singletonList(id));
            // 删除导入记录
            Document importRecord = document.get("importRecord", Document.class);
            importRecordService.deletByIds(Collections.singletonList(importRecord.getLong("id")));
            return true;
        }catch (Exception e){
            throw new ServiceException("删除模型数据失败");
        }
    }

    @Override
    public int save(MultipartFile file, IsfdModelBo isfdModelBo) {
        String originalFileName = file.getOriginalFilename();
        String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length());
        OssClient storage = OssFactory.instance();
        UploadResult uploadResult;
        try {
            uploadResult = storage.uploadSuffix(file.getBytes(), suffix);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
        // 保存文件信息
        saveModelDetail(originalFileName, suffix, storage.getConfigKey(), uploadResult, isfdModelBo);
        return 1;
    }

    @NotNull
    private void saveModelDetail(String originalfileName, String suffix, String configKey,
                                        UploadResult uploadResult, IsfdModelBo isfdModelBo) {
        Map<String, Object> paramsMap  = new HashMap<>();
        paramsMap.put("url", uploadResult.getUrl());
        paramsMap.put("applicable_models", isfdModelBo.getApplicableModels());
        paramsMap.put("model_name", isfdModelBo.getModelName());
        paramsMap.put("model_type", isfdModelBo.getModelType());
        paramsMap.put("model_series", isfdModelBo.getModelSeries());
        paramsMap.put("load_conditions", isfdModelBo.getLoadConditions());
        paramsMap.put("model_scope", isfdModelBo.getModelScope());
        paramsMap.put("business_scenarios", isfdModelBo.getBusinessScenarios());
        paramsMap.put("model_description", isfdModelBo.getModelDescription());
        paramsMap.put("source_methods",isfdModelBo.getSourceMethods());
        paramsMap.put("file_name", uploadResult.getFilename());
        paramsMap.put("original_name", originalfileName);
        paramsMap.put("file_suffix", suffix);
        paramsMap.put("service", configKey);
        //查询模型信息
        IsfdDatabaseModelConfig modelConfig = isfdDatabaseModelConfigMapper.selectModelByModelName("复合材料模型管理通用模型");
        // 记录record导入信息
        IsfdDatabaseDataImportRecordBo recordBo = new IsfdDatabaseDataImportRecordBo();
        IsfdBusinessDatabaseRefVo isfdBusinessDatabaseRefVo = isfdBusinessDatabaseRefMapper.selectDataBymodelId(modelConfig.getId());
        recordBo.setSceneId(isfdBusinessDatabaseRefVo.getSceneId());
        recordBo.setSystemId(isfdBusinessDatabaseRefVo.getSystemId());
        recordBo.setModelId(isfdBusinessDatabaseRefVo.getParentModelId());
        recordBo.setModelName(modelConfig.getModelName());
        recordBo.setTableName(modelConfig.getTableName());
        recordBo.setDatabaseTypeId(isfdBusinessDatabaseRefVo.getDatabaseTypeId());
        recordBo.setDataQuantity(1);

        String tableName = modelConfig.getTableName();
        Map<String, Integer> tableNameAndDataQuantity = new HashMap<>();
        tableNameAndDataQuantity.put(tableName, 1);
        IsfdDatabaseDataImportRecordBo dataImportRecordBo = importRecordService.createImportRecord(recordBo, IsfdImportMethodEnum.SITE, tableName, tableNameAndDataQuantity, LoginHelper.getLoginUser());
        try {
            // 构建mongo数据
            Map<String, Object> mongoBo = new HashMap<>();
            mongoBo.put("importMethod", dataImportRecordBo.getImportMethod());
            mongoBo.put("id", dataImportRecordBo.getId());
            mongoBo.put("createBy", dataImportRecordBo.getCreateBy());
            mongoBo.put("updateBy", dataImportRecordBo.getUpdateBy());
            mongoBo.put("createTime", dataImportRecordBo.getCreateTime());
            mongoBo.put("updateTime", dataImportRecordBo.getUpdateTime());
            mongoBo.put("delete_flag", 0);
            ObjectMapper objectMapper = new ObjectMapper();
            Map<String, Object> data = objectMapper.convertValue(paramsMap, new TypeReference<>() {
            });
            data.put("importRecord", mongoBo);
            // 保存数据
            String returnId = mongoService.save(modelConfig.getTableName(), data);
        } catch (Exception e) {
            // 删除导入记录
            isfdDatabaseDataManagementService.deleteDataByRecordId(dataImportRecordBo.getId());
            throw new ServiceException("模型数据保存失败");
        }
    }

    @Override
    public void download(String modelId, HttpServletResponse response) throws IOException {
        IsfdDatabaseModelConfig modelConfig = isfdDatabaseModelConfigMapper.selectModelByModelName("复合材料模型管理通用模型");
        Document document = mongoService.findById(modelConfig.getTableName(), modelId);
        if (ObjectUtil.isNull(document)) {
            throw new ServiceException("文件数据不存在!");
        }
        FileUtils.setAttachmentResponseHeader(response, document.getString("original_name"));
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
        OssClient storage = OssFactory.instance(document.getString("service"));
        long contentLength = storage.download(document.getString("file_name"), response.getOutputStream());
        response.setContentLengthLong(contentLength);
    }
    private IsfdCompositeModelVo matchingUrl(IsfdCompositeModelVo modelVo) {
        OssClient storage = OssFactory.instance(modelVo.getService());
        // 仅修改桶类型为 private 的URL，临时URL时长为120s
        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
            modelVo.setUrl(storage.getPrivateUrl(modelVo.getFileName(), 120));
        }
        return modelVo;
    }
}
